#include "definitions.h"


LinearFunction::LinearFunction(void)
{
  m_c = false;
  //m_symetric = new LinearFunction();
}

LinearFunction::~LinearFunction(void)
{
  //delete(m_symetric);
}


LinearFunction::LinearFunction(const double a, const double b, const bool c)
{
  this->m_a = a;
  this->m_b = b;
  this->m_c = c;
}
  
void LinearFunction::Create(const POINT & p1,const POINT & p2)
{
  if(p1.x - p2.x != 0)
  {
    m_a = (double)(p1.y - p2.y) / (double)(p1.x - p2.x);
    m_b = p1.y - (m_a * p1.x);
  }else
  {
    //just check if the points
    //y = -...<->.....+
    //x = x
    m_a = 0;
    m_b = p1.x;
    if(p1.x == p2.x && p1.y != p2.y)
      m_c = true;
  }
}



const POINT & LinearFunction::GetCommonPoint(const LinearFunction & func) // Will return the common point
{
  //POINT common;

  if(func.m_c || this->m_c)
  {
    if(func.m_c && this->m_c) //if both functions are constant 
    {
      if(func.m_b == this->m_b) //the both function are identical so all the points are common 
        throw EX_SAME_FUNCTIONS;
      else
        throw EX_EMPTY;
    }else
    {
      // one of the given functions are constant so the common point can be set easily
      if(func.m_c)
      {
        m_common.x = func.m_b;
        m_common.y = m_a * m_common.x + m_b;
      }else
      {
        m_common.x = this->m_b;
        m_common.y = func.m_a * m_common.x + func.m_b;
      }
    }
  }else
  {
    if((m_a == func.m_a) && (m_b == func.m_b))
    {
      //The both functions are the same so all points are common 
      throw EX_SAME_FUNCTIONS;
    }else
    {
      if((m_a != func.m_a) && (m_b != func.m_b)) //we have two different function we have to check if the common point not allign to any vector
      {
        m_common.x = (m_b - func.m_b) / (func.m_a - m_a);
        m_common.y = m_a * m_common.x + m_b;
      }
    }
  }
  return m_common;
}

const POINT & LinearFunction::CalculateValue(const POINT & p, const int set) // if second parameter is 0 function will calculate y otherwise x
{
  m_common = p;
  if(m_c)
  {
    if(set)
      m_common.x = m_b;
    else
      (p.x == m_b)?m_common.y = p.y:throw EX_WRONG_POINT; //only if (p.x == m_b)
  }else
  {
    if(set == 0) //calcualate y
    {
      m_common.y = m_a * m_common.x + m_b;
    }else
    {
      m_common.x = (m_common.y - m_b) / m_a;
    }
  }
  return m_common;
}

const LinearFunction & LinearFunction::GetSymetricFunction(const POINT & p)
{
  //m_symetric = 
  return(*m_symetric);
}

void LinearFunction::GetSymetricFunction(LinearFunction & lf,const POINT & p)
{
  //Symetric function has a simple property
  //new m_a parameter is equal -1/m_a old function

  //Test if a given point fulfill a given function
  
  if(lf.TestPoint(p))
  {
    if(lf.m_c)
    {
      m_a = 0;
      m_b = p.y;
    }else
    {
      if(lf.m_a == 0)
      {
        m_c = true;
        m_b = p.x;
        m_a = 0;
      }else
      {
        m_a = -1 / lf.m_a;
        m_b = p.y - (m_a * p.x);
      }
    }
  }else
    //return NULL;
   throw EX_WRONG_POINT;
  //return *this;
}

bool LinearFunction::TestPoint(const POINT & p)
{
  POINT _p;

  try{
    _p = CalculateValue(p, 0);
  }catch (int i)
  {
    if(i == EX_WRONG_POINT)
      return false;
  }

  return (p.y == _p.y)?true:false;
}


const float LinearFunction::Getangle(const LinearFunction & lf)
{
  //tg α = (a2 - a1)/(1 + a1 * a2)
  if(lf.m_c || this->m_c)
  {
    if(lf.m_a == 0 && this->m_a == 0)
    {
      //we have 90 degrees
      m_angle = 90;
    }else
    {
      //We have additionaly 2 cases when one function is constant and second is not , but the first of them 
      //1. lf is constatnt where y = b => angle = 0 and α of passed function is normal ( the eqution is correct)
      //2. lf is constant but where x = b => angle = 90 and α = | 90 - lf.α| and we can passed to equation
      //3. Both function has m_c = true so the α = 0
      //4. Both function hasn't m_c but m_a are = 0 so the angle is also = 0
      //
      //
    }
  }else
  {
    m_angle = (180 / PI) *(atan2((lf.m_a - m_a),(1 + lf.m_a * m_a)));

  }
  return m_angle;
}


const double LinearFunction::GetA()
{
  return m_a;
}
const double LinearFunction::GetB()
{
  return m_b;
}
const bool LinearFunction::GetC()
{
  return m_c;
}